/*
 * Copyright (c) 2014.
 * 游戏服务器核心代码编写人陈磊拥有使用权
 * 联系方式：E-mail:13638363871@163.com ;qq:502959937
 * 个人博客主页：http://my.oschina.net/chenleijava
 */

package nettyProxyEngine4;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author 石头哥哥 </br>
 *         dcServer1.7 </br>
 *         Date:14-2-24 </br>
 *         Time:下午3:27 </br>
 *         Package:{@link nettyProxyEngine4}</br>
 *         Comment：  终端连接代理服务器处理   代理服务器想目标服务器发起连接
 */
public class ProxyFrontendServerHandler extends ChannelInboundHandlerAdapter {

    private static final Logger LOGGER= LoggerFactory.getLogger(ProxyFrontendServerHandler.class);

    private final String remoteHost;

    private final int remotePort;

    private volatile Channel proxy_server_channel;   //


    /**
     * 终端连接代理服务器处理
     * @param remoteHost
     * @param remotePort
     */
    public ProxyFrontendServerHandler(String remoteHost, int remotePort) {
        this.remoteHost = remoteHost;
        this.remotePort = remotePort;
    }


    /**
     *  发起链接游戏服务器      建立代理服务器 和游戏服务器之间的socket的连接
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        final Channel client_proxy_channel = ctx.channel();
        LOGGER.debug(client_proxy_channel+" connect proxy server, start connect game server... ...");
        Bootstrap flexBoostStrap = new Bootstrap();
        flexBoostStrap.group(client_proxy_channel.eventLoop())
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.SO_REUSEADDR, true)     //重用地址
                .option(ChannelOption.ALLOCATOR, new PooledByteBufAllocator(false))// heap buf 's better
                .option(ChannelOption.SO_RCVBUF, 1048576)
                .option(ChannelOption.SO_SNDBUF, 1048576)
                .handler(new ProxyBackenServerHandler(client_proxy_channel));
        ChannelFuture channelFuture= flexBoostStrap.connect(remoteHost, remotePort);
        proxy_server_channel = channelFuture.channel();
        LOGGER.debug("connect game server "+remoteHost+":"+remotePort+"  success,begin to proxy");
        channelFuture.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                if (future.isSuccess()) {
                    // connection complete start to read first data
                    client_proxy_channel.read();
                } else {
                    // Close the connection if the connection attempt has failed.
                    client_proxy_channel.close();
                }
            }
        });
    }


    /**
     * Calls {@link io.netty.channel.ChannelHandlerContext#fireChannelRead(Object)} to forward
     * to the next {@link io.netty.channel.ChannelInboundHandler} in the {@link io.netty.channel.ChannelPipeline}.
     *
     * Sub-classes may override this method to change behavior.
     * 将来自客服端的数据推送到游戏服务器
     */
    @Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {

        /**
         * 指令根据具体的协议来指定
         * 接收到来之操作终端的指令  ，解析指令  ，向game server推送指令并返回给终端
         */
        ByteBuf messageBuf= (ByteBuf) msg;    //来自客户端的消息



        //将来自客户端的数据转发到游戏服务器
        if (proxy_server_channel.isActive()){
            proxy_server_channel.writeAndFlush(ReBuildBuf(messageBuf)).addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                        // was able to flush out data, start to read the next chunk
                        ctx.channel().read();
                    } else {
                        future.channel().close();
                    }
                }
            });
        }

    }

    /**
     * 重新构建被拦截的数据
     * @param messageBuf
     * @return
     */
    protected ByteBuf ReBuildBuf(ByteBuf messageBuf){
        ByteBuf buffer=PooledByteBufAllocator.DEFAULT.heapBuffer(0x80);
        buffer.setIndex(0, 0x2);//占位 2字节     数据包长
        buffer.writeBytes(messageBuf);
        buffer.setShort(0, buffer.writerIndex() - 0x2);
        messageBuf.release();
        return buffer;
    }

    /**
     * Calls {@link io.netty.channel.ChannelHandlerContext#fireChannelInactive()} to forward
     * to the next {@link io.netty.channel.ChannelInboundHandler} in the {@link io.netty.channel.ChannelPipeline}.
     *
     * Sub-classes may override this method to change behavior.
     *
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        closeOnFlush(proxy_server_channel);     //close proxy server channel after   all queued write requests are flushed.
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        closeOnFlush(ctx.channel());        //client_proxy_channel
    }

    /**
     * Closes the specified channel after all queued write requests are flushed.
     */
    static void closeOnFlush(Channel ch) {
        if (ch.isActive()) {
            ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        }
    }
}
